package org.kth.dks.dks_node;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.kth.dks.dks_comm.DKSRef;
import org.kth.dks.util.MathMisc;
/**
 * OrderDKSRefList keeps, from the perspeive of one DKSRef,  an ordered list of DKSRefs.
 * The ordering can either be increasing or decending (i.e. clockwise, or antoclockwise).
 */

class OrderedDKSRefList implements List {
    private LinkedList list= new LinkedList();
    private DKSRef     myDKSRef;
    private int        length;
    private long       addrRange;
    private boolean    clockwise;

    /**
     *
     * @param me  The DKSRef the list should be ordered on
     * @param len The maxlen of the list
     * @param ar  Address range (i.e. the size of the ring)
     * @param s   Sorting order, true for clockwise and false for anticlockwise
     */

    OrderedDKSRefList(DKSRef me, int len, long ar, boolean s ){
	myDKSRef  = me;
	length    = len;
	addrRange = ar;
	clockwise = s;
    }
    /**
     * returns the successor if clockwise (predecessor if !clockwise), the first node in the
     * frontlist,. Returns null if the list is empty.
     */
    public Object getFirst(){
	DKSRef ans = null;
	try {
	    ans = (DKSRef)  list.getFirst();
	} catch (Exception e){ }
	return ans;
    }

    /**
     *
     *
     */
    public boolean add(Object oref){
      DKSRef ref = (DKSRef)oref;
	for(int i = 0; i < list.size(); i ++){
	    DKSRef x = (DKSRef) list.get(i);
	    if(x.equals(ref)) return true;

            boolean insertHere;
	    if (clockwise)
              insertHere = MathMisc.belongsTo(ref.getID(), myDKSRef.getID(), x.getID(), addrRange);
	    else {
              insertHere = MathMisc.belongsTo(ref.getID(), x.getID(), myDKSRef.getID(), addrRange);
            }

	    if (insertHere) {
		list.add(i, ref);
		if(list.size() > length)
		    list.removeLast();
		return true;
	    }
	}

	if (list.size() < length){
	    list.addLast(ref);
	}
        return true;
    }

    // returns true if a node was removed, and thus the
    // list is too short.
    public boolean remove(Object ref){
	boolean ans = false;
	while(list.remove(ref)){
	    ans = true;
	}
	return ans;
    }

    public boolean checkLength(){
	return length == list.size();
    }

    public LinkedList toList(){
	return (LinkedList) list.clone();
    }

    public Object [] toArray(){
        return (DKSRef []) list.toArray(new DKSRef [0]);
    }

    public Object[] toArray(Object []arr) {
      return toArray();
    }

    public boolean contains(Object ref) {
	return list.contains(ref);
    }

    public boolean containsAll(Collection c) {
      return list.containsAll(c);
    }

    public String toString(){
	String ans = "";
	for(int i = 0; i < list.size(); i ++){
	    ans += ((DKSRef) list.get(i)).getID() + " ";
	}
	return ans;
    }

    public String toStringReverse(){
	String ans = "";
	for(int i = (list.size() - 1); i >= 0 ; i--){
	    ans += ((DKSRef) list.get(i)).getID() + " ";
	}
	return ans;
    }

    public Iterator iterator() {
      return list.iterator();
    }

    public ListIterator listIterator(){
	return list.listIterator();
    }

    public Object get(int i) {
      return list.get(i);
    }

    public ListIterator listIterator(int i) {
      return list.listIterator(i);
    }

    public List subList(int from, int to) {
      return list.subList(from, to);
    }

    public int indexOf(Object o) {
      return list.indexOf(o);
    }

    public int lastIndexOf(Object o) {
      return list.lastIndexOf(o);
    }

    public int size() {
      return list.size();
    }

    public void clear() {
      list.clear();
    }

    public boolean isEmpty() {
      return list.isEmpty();
    }

    public Object set(int index, Object el) {
      return new UnsupportedOperationException(); // optional in List
    }

    public boolean addAll(Collection c) {
      return false; // optional in List
    }

    public boolean addAll(int i, Collection c) {
      return false; // optional in List
    }

    public boolean  retainAll(Collection c) {
      return false; // optional in List
    }

    public boolean removeAll(Collection c) {
      return false; // optional in List
    }

    public Object remove(int i) {
      return new UnsupportedOperationException(); // optional in List
    }

    public void add(int i, Object o) {
      throw new UnsupportedOperationException(); // optional in List
    }

}
